package com.example.demo;

import com.alibaba.fastjson.JSON;
import com.example.demo.httpMessageConvert.*;
import com.example.demo.httpMessageConvert.weixin.AccessToken;
import com.example.demo.httpMessageConvert.weixin.menu.Menu;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

@Component
@Transactional(readOnly = true)
public class WeiXinService {

    @Autowired
    private Property property;

    private static HttpClient httpClient = HttpClients.createDefault();
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 获取客户端token
     *
     * @return
     * @throws IOException
     */
    public AccessToken getToken() throws IOException {
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair(UrlKey.APPID, property.getAppid()));
        params.add(new BasicNameValuePair(UrlKey.SECRET, property.getSecret()));
        params.add(new BasicNameValuePair(UrlKey.GRANT_TYPE, "authorization_code "));
        HttpGet httpGet = new HttpGet(property.getToken() + "?" + URLEncodedUtils.format(params, Charset.forName("UTF-8")));
        HttpResponse httpResponse = httpClient.execute(httpGet);
        // 获取返回数据
        HttpEntity httpEntity = httpResponse.getEntity();
        if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            String json = IOUtils.toString(httpEntity.getContent(), "utf-8");
            AccessToken accessToken = objectMapper.readValue(json, AccessToken.class);
            redisTemplate.opsForValue().set(RedisKey.ACCESS_TOKEN, accessToken);
            return accessToken;
        } else {
            return null;
        }
    }

    /**
     * 获取用户token
     *
     * @return
     * @throws IOException
     */
    public AccessToken getAccessToken(String code) throws IOException {

        if(redisTemplate.opsForHash().hasKey(RedisKey.CODE_OPPENID,code)){
            Object openid = redisTemplate.opsForHash().get(RedisKey.CODE_OPPENID, code);
            if(redisTemplate.opsForHash().hasKey(RedisKey.ACCESS_TOKEN_USER,openid)){
              return (AccessToken) redisTemplate.opsForHash().get(RedisKey.ACCESS_TOKEN_USER, openid);
            }
        }

        AccessToken accessToken = (AccessToken) redisTemplate.opsForValue().get(RedisKey.ACCESS_TOKEN);
        if (accessToken == null) {
            getToken();
        }
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair(UrlKey.APPID, property.getAppid()));
        params.add(new BasicNameValuePair(UrlKey.SECRET, property.getSecret()));
        params.add(new BasicNameValuePair(UrlKey.CODE, code));
        params.add(new BasicNameValuePair(UrlKey.GRANT_TYPE, "authorization_code"));
        HttpGet httpGet = new HttpGet(property.getAccess_token() + "?" + URLEncodedUtils.format(params, Charset.forName("UTF-8")));
        HttpResponse httpResponse = httpClient.execute(httpGet);
        // 获取返回数据
        HttpEntity httpEntity = httpResponse.getEntity();
        if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            String accessTokenJson = IOUtils.toString(httpEntity.getContent(), "utf-8");
            if (accessTokenJson.contains("errcode")) {
                Err err = objectMapper.readValue(accessTokenJson, Err.class);
                if (err.getErrcode().equals(40163)||err.getErrcode().equals(40029)) {
                    return null;
                }}
            AccessToken accessTokenUser = objectMapper.readValue(accessTokenJson, AccessToken.class);
            redisTemplate.opsForHash().put(RedisKey.ACCESS_TOKEN_USER, accessTokenUser.getOpenid(), accessTokenUser);
            redisTemplate.opsForHash().put(RedisKey.CODE_OPPENID,code,accessTokenUser.getOpenid());
            return accessTokenUser;
        }
        return null;
    }

    /**
     * 上传菜单
     *
     * @param menu
     * @return
     * @throws IOException
     */
    public Err menuCreate(Menu menu) throws IOException {
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        AccessToken accessToken = (AccessToken) redisTemplate.opsForValue().get(RedisKey.ACCESS_TOKEN);
        if (accessToken == null) {
            getToken();
        }
        params.add(new BasicNameValuePair(UrlKey.ACCESS_TOKEN, accessToken.getAccess_token()));
        HttpPost httpPost = new HttpPost(property.getMenuCreate() + "?" + URLEncodedUtils.format(params, Charset.forName("UTF-8")));
        httpPost.setEntity(new StringEntity(JSON.toJSONString(menu), Charset.defaultCharset()));
        HttpResponse httpResponse = httpClient.execute(httpPost);
        HttpEntity httpEntity = httpResponse.getEntity();
        if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            String json = IOUtils.toString(httpEntity.getContent(), "utf-8");
            Err err = objectMapper.readValue(json, Err.class);
            return err;
        } else {
            return null;
        }
    }

    /**
     * 获取用户信息
     *
     * @param accessTokenUser
     * @return
     * @throws IOException
     */
    public UserInfo getUserInfo(AccessToken accessTokenUser) throws IOException {
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair(UrlKey.ACCESS_TOKEN, accessTokenUser.getAccess_token()));
        params.add(new BasicNameValuePair(UrlKey.OPENID, accessTokenUser.getOpenid()));
        params.add(new BasicNameValuePair(UrlKey.LANG, "zh_CN"));
        HttpGet httpGetUserInfo = new HttpGet(property.getUserinfo() + "?" + URLEncodedUtils.format(params, Charset.forName("UTF-8")));
        HttpResponse httpResponseUserInfo = httpClient.execute(httpGetUserInfo);
        if (httpResponseUserInfo.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            HttpEntity httpEntity = httpResponseUserInfo.getEntity();
            String userInfoJson = IOUtils.toString(httpEntity.getContent(), "utf-8");
            if (userInfoJson.contains("errcode")) {
                Err err = objectMapper.readValue(userInfoJson, Err.class);
                if (err.getErrcode().equals(40003)) {
                    AccessToken accessTokenUserNew = refreshAccessTokenUser(accessTokenUser);
                    if(accessTokenUserNew==null)
                        return null;
                    else
                    return  getUserInfo(accessTokenUserNew);
                }
            }
            UserInfo userInfo = objectMapper.readValue(userInfoJson, UserInfo.class);
            return userInfo;
        }
        return null;
    }

    /**
     * 刷新token
     *
     * @param accessToken
     * @return
     * @throws IOException
     */
    public AccessToken refreshAccessTokenUser(AccessToken accessToken) throws IOException {
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair(UrlKey.APPID, property.getAppid()));
        params.add(new BasicNameValuePair(UrlKey.REFRESH_TOKEN, accessToken.getRefresh_token()));
        params.add(new BasicNameValuePair(UrlKey.GRANT_TYPE, "refresh_token"));
        HttpGet httpGet = new HttpGet(property.getRefresh_token() + "?" + URLEncodedUtils.format(params, Charset.forName("UTF-8")));
        HttpResponse httpResponse = httpClient.execute(httpGet);
        // 获取返回数据
        HttpEntity httpEntity = httpResponse.getEntity();
        if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            String accessTokenJson = IOUtils.toString(httpEntity.getContent(), "utf-8");
            if (accessTokenJson.contains("errcode")) {
                Err err = objectMapper.readValue(accessTokenJson, Err.class);
                if (err.getErrcode().equals(40029)) {
                  return null;
                }
            }
            AccessToken accessTokenUser = objectMapper.readValue(accessTokenJson, AccessToken.class);
            redisTemplate.opsForHash().put(RedisKey.ACCESS_TOKEN_USER, accessTokenUser.getOpenid(), accessTokenUser);
            return accessTokenUser;
        }
        return null;
    }

   /* public Err auth() throws IOException {
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair(UrlKey.APPID, property.getAppid()));
        params.add(new BasicNameValuePair(UrlKey.SECRET, property.getSecret()));
        params.add(new BasicNameValuePair(UrlKey.GRANT_TYPE, "client_credential"));
        HttpGet httpGet = new HttpGet(property.getAccessTokenUrl() + "?" + URLEncodedUtils.format(params, Charset.forName("UTF-8")));
        HttpResponse httpResponse = httpClient.execute(httpGet);
        // 获取返回数据
        HttpEntity httpEntity = httpResponse.getEntity();
        if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            String json = IOUtils.toString(httpEntity.getContent(), "utf-8");
            Err err = objectMapper.readValue(json, Err.class);
            return err;
        } else {
            return null;
        }
    }*/
}
